package br.ufc.apsoo.repositories;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import br.com.caelum.vraptor.ioc.Component;
import br.ufc.apsoo.models.Despesa;
import br.ufc.apsoo.models.Servico;

@Component
public class ServicoRepositoryImpl extends Repository<Servico, Long> implements
		TodosServicos {

	private final Session session;

	protected ServicoRepositoryImpl(EntityManager entityManager) {
		super(entityManager);
		session = (Session) entityManager.getDelegate();
	}

	public void adiciona(Servico servico) {
		this.create(servico);
	}

	@Override
	public List<Servico> ativos() {
		Criteria criteria = session.createCriteria(Servico.class);

		criteria.add(Restrictions.eq("ativo", true));
		criteria.addOrder(Order.asc("id"));

		return criteria.list();
	}

	public void atualiza(Servico servico) {
		this.update(servico);
	}

	public void desativaEste(Servico servico) {
		servico = this.trazPorId(servico.getId());
		servico.desativa();
		this.atualiza(servico);
	}

	public List<Servico> listaPor(Servico servico) {
		Criteria criteria = session.createCriteria(Servico.class);

		if (servico != null) {
			if (servico.getDescricao() != null
					&& !servico.getDescricao().isEmpty()) {
				criteria.add(Restrictions.like("descricao",
						servico.getDescricao(), MatchMode.ANYWHERE)
						.ignoreCase());
			}
		}
		criteria.addOrder(Order.asc("id"));

		return criteria.list();
	}

	private List<Servico> objetoParaDespesa(List<Object[]> lista) {

		List<Servico> servicos = new ArrayList<Servico>();
		Servico servico = null;
		for (Object[] obj : lista) {
			servico = new Servico();
			servico.setFaturamento((BigDecimal) obj[0]);
			servico.setId((Long) obj[1]);
			servico.setDescricao((String) obj[2]);
			servicos.add(servico);
		}

		return servicos;

	}

	@Override
	public List<Servico> queMaisFaturaramEntre(Date dataInicio, Date dataFim) {
		Criteria criteria = session.createCriteria(Despesa.class);
		criteria.createAlias("servico", "servico");
		criteria.setProjection(Projections.projectionList()
				.add(Projections.sum("servico.valor"), "servico.faturamento")
				.add(Projections.groupProperty("servico.id"))
				.add(Projections.groupProperty("servico.descricao")));
		criteria.add(Restrictions.between("data", dataInicio, dataFim));
		criteria.addOrder(Order.desc("servico.faturamento"));

		return objetoParaDespesa(criteria.list());
	}

	public Servico trazPorId(Long id) {
		return (Servico) this.find(id);
	}

}
